﻿using System;
using System.Data.Common;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using DLM.Data.EF.CodeFirst.Mapping;
using DLM.Domain.Model;
using DLM.Infrastructure.UnitOfWork;
using System.Reflection;
using System.Linq;

namespace DLM.Data.EF.CodeFirst
{
    public class DLMEntities:DbContext,IDbContext
    {
        private static readonly string conStr = System.Configuration.ConfigurationManager.ConnectionStrings["DLMEntities"].ConnectionString;
        private static string DefaultSchema;
        static DLMEntities()
        {
            //Database.SetInitializer<DLMEntities>(new DropCreateDatabaseIfModelChanges<DLMEntities>());
            //DefaultSchema = "douom12";
           
        }

        //public DLMEntities()
        //    : base("name=DLMEntities")
        //{
 
        //}

        public DLMEntities()
            : base(conStr)
        {
            this.Configuration.LazyLoadingEnabled = false;
            this.Configuration.ProxyCreationEnabled = false;
            
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.OneToManyCascadeDeleteConvention>();
            // modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.ForeignKeyAssociationMultiplicityConvention>();

            modelBuilder.Configurations.Add(new AccountMap());
            modelBuilder.Configurations.Add(new AdminLogMap());
            modelBuilder.Configurations.Add(new AdminUserMap());
            modelBuilder.Configurations.Add(new BonusMap());
            modelBuilder.Configurations.Add(new EmailInvitationMap());
            modelBuilder.Configurations.Add(new FriendMap());
            modelBuilder.Configurations.Add(new InvitationMap());
            modelBuilder.Configurations.Add(new LogMap());
            modelBuilder.Configurations.Add(new MessageMap());
            modelBuilder.Configurations.Add(new NoticeMap());
            modelBuilder.Configurations.Add(new PartyMap());
            modelBuilder.Configurations.Add(new PhotoMap());
            modelBuilder.Configurations.Add(new RemarkMap());
            modelBuilder.Configurations.Add(new UserMap());
            modelBuilder.Configurations.Add(new UserPartyAssociationMap());
            modelBuilder.Configurations.Add(new UserViewMap());
            modelBuilder.Configurations.Add(new BonusLogMap());
            modelBuilder.Configurations.Add(new SalutationMap());
            modelBuilder.Configurations.Add(new TypeMap());
            modelBuilder.Configurations.Add(new ModalityMap());
            modelBuilder.Configurations.Add(new SupplierMap());
            modelBuilder.Configurations.Add(new BreakAppointmentMap());
            modelBuilder.Configurations.Add(new BonusCalculateStepMap());
            modelBuilder.Configurations.Add(new PartyAlbumMap());
            modelBuilder.Configurations.Add(new OrderMap());

            if (!String.IsNullOrEmpty(DefaultSchema))
            {
                var entityMethod = modelBuilder.GetType().GetMethod("Entity");
                foreach (PropertyInfo dbSet in GetType().GetProperties().Where(t => t.PropertyType.IsGenericType && t.PropertyType.GetGenericTypeDefinition().Equals(typeof(DbSet<>))))
                {
                    var entityType = dbSet.PropertyType.GetGenericArguments();
                    var entityMethodGeneric = entityMethod.MakeGenericMethod(entityType);
                    var entityGeneric = entityMethodGeneric.Invoke(modelBuilder, null);
                    var tableName = GetTableName(entityGeneric);
                    if (String.IsNullOrEmpty(tableName)) continue;
                    entityGeneric.GetType().InvokeMember("ToTable", BindingFlags.InvokeMethod, null, entityGeneric, new object[] { tableName, DefaultSchema });
                }
            }

        }

        public DbSet<Account> Account { get; set; }
        public DbSet<AdminLog> AdminLog { get; set; }
        public DbSet<AdminUser> AdminUser { get; set; }
        public DbSet<Bonus> Bonus { get; set; }
        public DbSet<EmailInvitation> EmailInvitation { get; set; }
        public DbSet<Friend> Friend { get; set; }
        public DbSet<Invitation> Invitation { get; set; }
        public DbSet<Log> Log { get; set; }
        public DbSet<Message> Message { get; set; }
        public DbSet<Notice> Notice { get; set; }
        public DbSet<Party> Party { get; set; }
        public DbSet<Photo> Photo { get; set; }
        public DbSet<Remark> Remark { get; set; }
        public DbSet<User> User { get; set; }
        public DbSet<UserPartyAssociation> UserPartyAssociation { get; set; }
        public DbSet<UserView> UserView { get; set; }
        public DbSet<BonusLog> BonusLog { get; set; }
        public DbSet<Salutation> Salutation { get; set; }
        public DbSet<DLM.Domain.Model.Type> Type { get; set; }
        public DbSet<Modality> Modality { get; set; }
        public DbSet<Supplier> Supplier { get; set; }
        public DbSet<BreakAppointment> BreakAppointment { get; set; }
        public DbSet<BonusCalculateStep> BonusCalculateStep { get; set; }
        public DbSet<PartyAlbum> PartyAlbum { get; set; }
        public DbSet<Order> Order { get; set; }


        public System.Linq.IQueryable<T> Find<T>() where T : class
        {
            return this.Set<T>();
        }

        internal string GetTableName(object entityGeneric)
        {
            var tableName = String.Empty;

            //-- Try looking on Fluent API declaration
            var entityConfig = entityGeneric.GetType().InvokeMember("_entityTypeConfiguration", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, entityGeneric, new object[] { });
            var databaseName = entityConfig.GetType().InvokeMember("GetTableName", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, entityConfig, new object[] { });
            if (databaseName != null)
                tableName = (string)databaseName.GetType().InvokeMember("ToString", BindingFlags.InvokeMethod, null, databaseName, new Object[] { });

            if (!String.IsNullOrEmpty(tableName)) return tableName;

            //-- Try looking on DataAnnotation
            var entity = entityGeneric.GetType().GetGenericArguments().FirstOrDefault();
            if (entity != null)
            {
                var tableAttribute = entity.GetCustomAttributes(false).OfType<System.ComponentModel.DataAnnotations.TableAttribute>().FirstOrDefault();
                tableName = tableAttribute == null ? String.Empty : tableAttribute.Name;
            }

            //-- Use the EF convention if not found
            if (String.IsNullOrEmpty(tableName))
                tableName = (string)entityConfig.GetType().InvokeMember("_entitySetName", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance, null, entityConfig, new object[] { });

            return tableName;
        }
    }

}
